import { Vector2tuple, Vector3 } from 'three-legacy';

import {
  SKETCH_CENTEREVENTS,
  sketchEventCenter,
} from '../../../events/SketchEventCenter';
import {
  CadScene,
  CSys,
  EventsRes,
  ICurve,
  KEYBOARD_KEY,
  MathTool,
  MouseInfo,
  SceneGraph,
  SceneSetup,
  SketchFrame,
} from '@amcax/base';
import { ctx2 } from '@app-cad/module';
import { wsApi } from '@app-cad/server';
import { MouseState, State } from './types';
import { debounce } from 'lodash';
import {
  renderSketch,
  sketchPreview,
  updataRenderDim,
} from '@app-cad/common/utils';
import { Picker2D, PickerMgr } from '@amcax/renderer';
export class CmdInteractor {
  point: Vector3;
  mousePoint: string | Vector2tuple;
  currentParams: string;
  currentState: MouseState = State.DRAW;
  // 草图数据
  public sketchData: ICurve[];
  protected exitFunc = () => {};

  private planeNormal: Vector3;
  private planeOrigin: Vector3;
  public faceCSys: CSys;
  public assisGroup: THREE.Object3D;
  private cadScene: CadScene;
  private sceneSetup: SceneSetup;
  public sketchFrame: SketchFrame;
  private lastParams: string;
  debounceOnPointUp;
  debounceOnPointMove;
  private frame: number[][];
  private firstClick: boolean;
  private sketchId: string = sketchEventCenter().getSketchInfo().sketchId;
  protected picker = PickerMgr.getPicker<Picker2D>('2d');

  constructor() {
    this.frame = sketchEventCenter().getSketchInfo().frame;
    this.cadScene = ctx2.cadScene as CadScene;
    this.assisGroup = this.cadScene.assisGroup;

    this.sceneSetup = ctx2.viewer.sceneSetup;
    this.lastParams = '';
    this.sketchFrame = new SketchFrame(this.frame);
    this.faceCSys = MathTool.createCsysFromPlacement(this.frame);
    this.planeNormal = this.faceCSys.getNormalVc3();
    this.planeOrigin = this.faceCSys.getOriginVc3();
    this.debounceOnPointUp = debounce(this.onPointUp, 50);
    this.debounceOnPointMove = debounce(this.onPointMove, 50);
    this.firstClick = false;
    this.registerEvents();
  }
  public registerEvents() {
    sketchEventCenter()
      .setState('trim')
      .on(SKETCH_CENTEREVENTS.POINTERMOVE, this.debounceOnPointMove)
      .on(SKETCH_CENTEREVENTS.POINTERUP, this.onPointUp)
      .on(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp)
      .addExit(this.destory.bind(this));
  }
  public unregisterEvents() {
    sketchEventCenter()
      .off(SKETCH_CENTEREVENTS.POINTERMOVE, this.debounceOnPointMove)
      .off(SKETCH_CENTEREVENTS.POINTERUP, this.onPointUp)
      .off(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp)
      .setDefault();
  }
  protected onKeyUp = (e: EventsRes<KeyboardEvent>) => {
    if (e.key === KEYBOARD_KEY.ESC) {
      this.exitFunc?.();
    }
  };
  destory() {
    // 移除约束
    this.reset();

    this.unregisterEvents();
    this.releaseObjects();
    SceneGraph.emptyGroup(this.assisGroup);
  }
  protected getPointByMouse(mouse: MouseInfo) {
    const mousePoint = this.sceneSetup.mouseOnPlane(
      mouse.x,
      mouse.y,
      this.planeNormal,
      this.planeOrigin,
    );
    return this.sketchFrame.toLocal(mousePoint);
  }
  public addExit(exitFunc: () => void) {
    this.exitFunc = exitFunc;
  }

  onPointMove = async (e: EventsRes) => {
    ctx2.cadScene.assisGroup.clear();
    this.point = this.getPointByMouse(e.mouse).clone();
    const info = this.picker.pick(e, { line: true });
    if (info && info.id && info.id !== 'X-AXIS' && info.id !== 'Y-AXIS') {
      this.currentParams = info.id;
      if (
        JSON.stringify(this.currentParams) !== JSON.stringify(this.lastParams)
      ) {
        // 计算鼠标点和两个端点之间的距离
        const terminalPoint1 = new Vector3(
          info.vertices[0][0],
          info.vertices[0][1],
          0,
        );
        const terminalPoint2 = new Vector3(
          info.vertices[1][0],
          info.vertices[1][1],
          0,
        );
        const length1 = this.point.distanceTo(terminalPoint1);
        const length2 = this.point.distanceTo(terminalPoint2);
        if (length1 < 10 / ctx2.getCameraZoom()) {
          this.mousePoint = info.vertices[0];
        } else if (length2 < 10 / ctx2.getCameraZoom()) {
          this.mousePoint = info.vertices[1];
        } else {
          this.mousePoint = [this.point.x, this.point.y];
        }

        this.lastParams = this.currentParams;

        const res = await wsApi.trimSketcherCurve(
          this.sketchId,
          this.currentParams,
          this.mousePoint,
          true,
        );
        if (res && !this.firstClick) {
          sketchPreview(res.curves);
          this.firstClick = true;
        }
      }
    } else {
      this.assisGroup.clear();
      ctx2.viewer.requestRender();
      this.lastParams = '';
      this.firstClick = false;
    }
  };

  onPointUp = async (e: EventsRes) => {
    if (e.button.onLeft && this.firstClick) {
      this.firstClick = false;
      const info = this.picker.pick(e, { line: true });
      if (info && info.id && info.id !== 'X-AXIS' && info.id !== 'Y-AXIS') {
        const res = await wsApi.trimSketcherCurve(
          this.sketchId,
          this.currentParams,
          this.mousePoint,
          false,
        );

        await renderSketch(this.sketchId, res);
        await updataRenderDim(this.sketchId);
      }
    }
  };

  reset() {}
  releaseObjects() {
    this.assisGroup.clear();
    this.picker.clickNull();
    SceneGraph.emptyGroup(this.assisGroup);
    ctx2.viewer.requestRender();
  }
}
